#include "tcp_server.h"

#define LOCAL_BUF     10
#define LACK_ARGs     "使用方法: ./server <ip> <port>"
#define FINISH_WORD   "quit"
#define DATABASE_NAME "mydatabase.db"


static const int MAX_ACCEPT_NUMs  = 1000;
static const int MAX_EPOLL_EVENTs = 1024;


int main(int argc, const char *argv[])
{
	/* check arguments amount */
	if (argc < 3) {
		printf("%s\n", LACK_ARGs);
		return 0;
	}

	/* variable defination */
	char               buf[LOCAL_BUF];
	int                ret, i, listen_fd, client_fd, epoll_fd, ready_max;
	socklen_t          client_addr_len;
	struct sockaddr_in server_addr, client_addr;
	struct epoll_event ev, *ready_event = NULL;
	sqlite3* db;

	/* establish socket */
	listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_fd == -1) {
		PRINT_ERR("socket create");
		goto end_step_1;
	}

	/* bind socket */
	bzero(&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family      = AF_INET;
	server_addr.sin_port        = htons((short)atoi(argv[2])); 
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);
	if (server_addr.sin_addr.s_addr == -1) {
		PRINT_ERR("inet_addr");
		goto end_step_2;
	}

	if (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) == -1) {
		PRINT_ERR("bind");
		goto end_step_2;
	}

	/* listen */
	if (listen(listen_fd, MAX_ACCEPT_NUMs) == -1) {
		PRINT_ERR("listen");
		goto end_step_2;
	}

	/* epoll init */	
	/* epoll create */
	epoll_fd = epoll_create(1);
	if (epoll_fd == -1) {
		PRINT_ERR("epoll_create");
		goto end_step_2;
	}

	/* epoll add */
	ev.events  = EPOLLIN;
	ev.data.fd = listen_fd;
	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev) == -1) {
		PRINT_ERR("epoll add listen_fd");
		goto end_step_3;
	}
	ev.data.fd = STDIN_FILENO;
	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1) {
		PRINT_ERR("epoll add stdin");
		goto end_step_3;
	}
	ready_event = (struct epoll_event*) malloc(MAX_EPOLL_EVENTs * sizeof(struct epoll_event));
	if (!ready_event) {
		PRINT_ERR("malloc ready_event");
		goto end_step_4;
	}

	/* sql */
	/* open */
	if (dataOpen(DATABASE_NAME, &db) == Failure) {
		goto end_step_4;
	}
	/* create table */ 
	if (dataCreatTable(db, TABLE_ACCOUNT, ACCOUNT_ITEM) == Failure) {
		goto end_step_5;
	}
	if (dataCreatTable(db, TABLE_STAFF, STAFF_ITEM) == Failure) {
		goto end_step_5;
	}
	if (dataCreatTable(db, TABLE_HISTORY, HISTORY_ITEM) == Failure) {
		goto end_step_5;
	}
	
	/* begin service */
	for (;;)
	{
		ready_max = epoll_wait(epoll_fd, ready_event, MAX_EPOLL_EVENTs, -1);
		if (ready_max == -1) {
			PRINT_ERR("epoll_wait");
			goto end_step_4;
		}

		/* handle ready fd */
		bzero(&client_addr, sizeof(struct sockaddr_in));
		
		client_addr_len = sizeof(struct sockaddr);
		
		for (i = 0; i < ready_max; ++i) 
		{
			/* accept */
			if (ready_event[i].data.fd == listen_fd)
			{
				client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_addr_len);
				if (client_fd == -1) {
					PRINT_ERR("accept");
					goto end_step_4;
				}

				ev.data.fd = client_fd;
				if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
					PRINT_ERR("epoll add client_fd");
					goto end_step_4;
				}

				/* show client online */
				printf("client[%s, %d, %d] online\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), client_fd);
			}
			else if (ready_event[i].data.fd == STDIN_FILENO) 
			{
				ret = read(STDIN_FILENO, buf, LOCAL_BUF);
				if (ret <= 0) {
					INPUT_ERR;
					goto end_step_5;
				}
				if (buf[ret-1] != '\n') {
					while (getchar() != '\n');
				}
				buf[ret-1] = '\0';
				if (strcmp(buf, FINISH_WORD) == 0) {
					goto end_step_4;
				} else {
					printf("输入 %s 退出\n", FINISH_WORD);
					continue;
				}
			}
			else
			{
				/* communicate with client */
				if (doService(ready_event[i].data.fd, epoll_fd, db) == Failure) {
					PRINT_ERR("Server abort!");
					goto end_step_4;
				}
			} /* end of if */
		} /* end of for */
	} /* end of for(;;) */

end_step_5:
	dataClose(db);
end_step_4:
	free(ready_event);
end_step_3:
	close(epoll_fd);
end_step_2:
	close(listen_fd);
end_step_1:
	return 0;
}

